/*************************************************************************
** Name		: xCores.h
** Desc		: 基于系统api实现的多线程辅助工具。目的：简化多线程的使用
** Author	: xktesla
*************************************************************************/

#ifndef _80AF3CDF_5146_4BD2_89B3_B6E7D9CECEC2
#define _80AF3CDF_5146_4BD2_89B3_B6E7D9CECEC2

#include "depends/incfile.h"

namespace x2lib
{

namespace xCores
{
	/*************************************************************************
	** Name		: 仿java终结类
	** Desc		: 仿java的final关键字，使用方法：虚继承之
	** Author	: xktesla
	*************************************************************************/
	template <class T>
	class Final
	{
		friend T;
	private:
		Final() {}
		Final(const Final&) {}
	};

	// 基于该源码修改：https://blog.csdn.net/dxgzg/article/details/112368056
	class MutexRW
	{
	public:
		MutexRW(bool isPreferWriter = false) :preferWriter(isPreferWriter) {}

		void LockR() {
			std::unique_lock<std::mutex>lock(mx);
			++readWaiting;
			// preferWriter靠这个来让写锁优先了
			//cond.wait(lock, [&]() {return writing <= 0 && (!preferWriter || writeWaiting <= 0); });
			// 读锁优先
			cond.wait(lock, [&]() {return writing <= 0;});
			++reading;
			--readWaiting;
		}

		void LockW() {
			std::unique_lock<std::mutex>lock(mx);
			++writeWaiting;
			// 这里规定writing<=0才能继续执行，保证了写的时候进入一次，reading <= 0 保证了读的优先
			cond.wait(lock, [&]() {return readWaiting <= 0 && reading <= 0 && writing <= 0; });
			++writing;
			--writeWaiting;
		}

		void UnLockR() {
			std::unique_lock<std::mutex>lock(mx);
			--reading;
			//当前没有读者时，唤醒一个写者
			if (reading <= 0)
				cond.notify_one();
		}

		void UnLockW() {
			std::unique_lock<std::mutex>lock(mx);
			--writing;
			//唤醒所有读者、写者
			cond.notify_all();
		}

	private:
		int readWaiting = 0;  //等待读
		int writeWaiting = 0; //等待写
		int reading = 0; //正在读
		int writing = 0;  //正在写
		std::mutex mx;
		std::condition_variable cond;
		bool preferWriter;  //偏向读
	};

	/**
	* @brief        互斥锁，基于系统api实现
    * @author       xktesla
	*/
	class Mutex : virtual Final<Mutex>
	{
	public:
		Mutex();
		virtual ~Mutex();

        bool Lock() const;
        bool Unlock() const;

	private:
#ifdef __X2LIB_WIN32__
		int m_mutex;
#elif defined __X2LIB_LINUX__
		pthread_mutex_t m_mutex;
#endif
	};

#if 0
	/**
	* @brief        信号量，基于系统api实现
	* @author       xktesla
	*/
	class Signal: virtual Final<Signal>
	{
	public:
        Signal(int iInit, int iMax, char* pName/*[128]*/=nullptr);
		~Signal();

		/*************************************************************************
		** Desc		: 使用构造函数参数重置
		** Author	: xktesla
		*************************************************************************/
		void Reset();

		/*************************************************************************
		** Desc		: 重置
		** Param	: [in] iInit 初始值
		** Param	: [in] iMax 最大值
		** Author	: xktesla
		*************************************************************************/
		void Reset(int iInit, int iMax);

		/*************************************************************************
		** Desc		: 等待
		** Param	: [in] uWaitms, -1表示无限等待
		** Return	: 返回时是否触发了超时
		** Author	: xktesla
		*************************************************************************/
		bool Wait(uint64_t uWaitms = -1) const;
		bool Notify(int nCnt = 1) const;

	private:
		int m_signal; // linux sem_id
		union semun{
			int val;
			struct semid_ds *buf;
			unsigned short *arry;
		};

        int m_iInit, m_iMax;
        char m_szName[128];
	};

#else
#ifndef __X2LIB_MACOS__
#include <condition_variable>
#endif
    class Signal
    {
    public:
        explicit Signal(int count = 0) : count_(count) {}

        void Release(int count = 1)
        {
            std::unique_lock<std::mutex> lock(mutex_);
            count_ += count;
            for (int i = 0; i < count; ++i) { cv_.notify_one(); }
        }

        bool Acquire(int count = 1, uint32_t uWaitms = (uint32_t)-1)
        {
            std::unique_lock<std::mutex> lock(mutex_);
			bool ret = true;
			if (uWaitms != (uint32_t)-1)
			{
            	ret = cv_.wait_for(lock, std::chrono::milliseconds(uWaitms), [this,count]() { return count_ >= count; });
			}
			else
			{
				cv_.wait(lock, [this,count]() { return count_ >= count; });
			}
            count_ -= count;
			return ret;
        }

    private:
        std::mutex mutex_;
        std::condition_variable cv_;
        int count_;
    };
#endif

    /**
	* @brief        线程引擎类，基于系统api实现，将线程执行函数以成员函数的方式执行
    * @author       xktesla
	*/
    class Engine
	{
	public:
		enum EState
		{
			EState_Spare = 0,  // 空闲
			EState_Start, // 已启动
			EState_Pause, // 已暂停
			EState_Locked // 已锁定
		};


		/**
		* @brief        构造
		* @param[in]    nMax 允许最大线程数
		* @return
		* @author       xktesla
		*/
        Engine(uint16_t nMax = 8);
        virtual ~Engine();

		/**
		* @brief        启动一个线程
		* @param[in]    vData 预留给用户
		* @return		失败返回0，否则返回线程id
		* @author       xktesla
		*/
        uint32_t Ignite(void* vData);

		/**
		* @brief        停止一个线程
		* @param[in]    id 线程id
		* @param[in]    uWiatms 最大等待时长
		* @return		若等待超时则返回true，否则返回false
		* @author       xktesla
		*/
        bool Stall(uint32_t id, uint32_t uWiatms = 3000);

		/**
		* @brief        挂起线程，不推荐使用，linux可参考：https://blog.csdn.net/weixin_33490603/article/details/116775747
		* @param[in]    id 线程id
		* @return		
		* @author       xktesla
		*/
		void Suspend(uint32_t id);

		/**
		* @brief        恢复线程，不推荐使用，linux可参考：https://blog.csdn.net/weixin_33490603/article/details/116775747
		* @param[in]    id 线程id
		* @return		
		* @author       xktesla
		*/
		void Resume(uint32_t id);

		/**
		* @brief        获取线程状态
		* @param[in]    id 线程id
		* @return		线程状态枚举
		* @author       xktesla
		*/
		EState GetState(uint32_t id);

		/**
		* @brief        获取当前线程id
		* @return		失败返回0，否则为当前线程id
		* @author       xktesla
		*/
		static uint32_t GetCurId();

		bool startTimer(uint32_t timerId, uint32_t msPeriod, void (*timerProc)(uint32_t, void*), void* vData);
		void stopTimer(uint32_t timerId);

	protected:
		/**
		* @brief        由Ignite触发
		* @param[in]    id 线程id
		* @param[in]    vData Ignite传入的用户参数
		* @return		
		* @author       xktesla
		*/
		virtual void onEngineExec(uint32_t id, void* vData) = 0;

		/**
		* @brief        由Stall触发，若调用Stall时线程已结束则不会触发
		* @param[in]    id 线程id
		* @param[in]    vData Ignite传入的用户参数
		* @return
		* @author       xktesla
		*/
		virtual void onEngineExit(uint32_t id, void* vData) = 0;

	private:
		struct Info
		{
			Info();
			~Info();
			void Reset();

			uint64_t n_tid;
			void* handle;
			Signal signal;
			EState state;
			void* vData;
			Engine* pThis;
		};

		// 忽略EState_Spare和EState_Locked
		Info* getInfoById(uint32_t id);
		Info* getFreeInfo();
		static void* threadProc(void *p);

		Info* m_pInfos;
		int m_nInfos;
		std::map<int, std::tuple<bool, std::condition_variable*, std::thread*>> m_mapTimer;
	};

	template<class T>
	class MsgQue : public virtual Final<MsgQue<T> > // linux error: '>>' should be '> >' within a nested template argument list
	{
	public:
		struct QMSG
		{
		public:
			QMSG()
			{
				memset(this, 0, sizeof(QMSG));
			}
			QMSG(int iArg0, int iArg1, void *vArg2, char sArg3[1024],bool isSend)
			{
				this->iArg0 = iArg0;
				this->iArg1 = iArg1;
				this->vArg2 = vArg2;
				this->sArg3[0] = 0;
				if (sArg3)strcpy(this->sArg3, sArg3);
				this->isSend = isSend;
			}
			int iArg0;
			int iArg1;
			void *vArg2;
			char sArg3[1024];
		private:
			bool isSend;
			friend class MsgQue;
		};

		MsgQue(int iCapcity=8)
		{
			for (int i = 0; i < iCapcity; i++)
			{
				m_Store.push(new QMSG());
			}
		}
		~MsgQue()
		{
			while (m_Store.size())
			{
				QMSG *qMsg = m_Store.front();
				m_Store.pop();
				delete qMsg;
			}
		}

		bool Post(int iArg0, int iArg1, void *vArg2, char sArg3[1024], bool isSend = false)
		{
			m_Mutex0.Lock();
			QMSG *pMsg = m_Store.front();
			m_Store.pop();
			m_Mutex0.Unlock();
			*pMsg = QMSG(iArg0, iArg1, vArg2, sArg3, isSend);
			//memcpy(pMsg, &qmsg, sizeof(QMSG));
			m_Mutex1.Lock();
			m_msgQue.push(pMsg);
			m_Mutex1.Unlock();
			m_SigPost.Release(1);
			return true;
		}

		bool Send(int iArg0, int iArg1, void *vArg2, char sArg3[1024])
		{
			Post(iArg0, iArg1, vArg2, sArg3, true);
			m_SigSend.Acquire();
			//return (*pMsg);
			return true;
		}

		template<typename b_i_i_v_s>
		void Loop(b_i_i_v_s pfnMsgLoop, T *pThis)
		{
			do
			{
				m_SigPost.Acquire();
				m_Mutex1.Lock();
				QMSG *qMsg = m_msgQue.front();
				m_msgQue.pop();
				m_Mutex1.Unlock();
				bool bContinue = (pThis->*pfnMsgLoop)(qMsg->iArg0, qMsg->iArg1, qMsg->vArg2, qMsg->sArg3);
				if (qMsg->isSend)
				{
					m_SigSend.Release(1);
				}
				m_Mutex0.Lock();
				m_Store.push(qMsg);
				m_Mutex0.Unlock();
				if (!bContinue)break;
			} while (true);
		}

	public:
		Mutex m_Mutex0; // m_Store
		Mutex m_Mutex1; // m_msgQue
		Signal m_SigPost;
		Signal m_SigSend;
		std::queue<QMSG*> m_msgQue; 
		std::queue<QMSG*> m_Store;
	};
}

}

#endif

